#include "seq_queue.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

int queue_init(Queue **qu, size_t size, size_t capacity) {
  (*qu) = malloc(sizeof(Queue));
  if ((*qu) == NULL) {
    return -1;
  }
  (*qu)->data = malloc(size * (capacity));
  if ((*qu)->data == NULL) {
    free(*qu);
    (*qu) = NULL;
    return -1;
  }
  (*qu)->size = size;
  (*qu)->capacity = capacity;
  (*qu)->front = 0;
  (*qu)->back = 0;
  return 0;
}

int queue_empty(const Queue *qu) { return qu->back == qu->front; }
int queue_full(const Queue *qu) {
  return (qu->back + 1) % qu->capacity == qu->front;
}
size_t queue_nmemb(const Queue *qu) {
  return ((qu->back - qu->front) + qu->capacity) % qu->capacity;
}

void *queue_front(const Queue *qu) {
  if (queue_empty(qu)) {
    return NULL;
  }
  return (char *)qu->data + (qu->front * qu->size);
}

void *queue_back(const Queue *qu) {
  if (queue_empty(qu)) {
    return NULL;
  }
  return (char *)qu->data +
         (((qu->back - 1 + qu->capacity) % qu->capacity) * qu->size);
}

int queue_push(Queue *qu, void *data) {
  if (queue_full(qu)) {
    return -1;
  }
  memcpy((char *)qu->data + qu->back * qu->size, data, qu->size);
  qu->back = (qu->back + 1) % qu->capacity;
  return 1;
}

int queue_pop(Queue *qu) {
  if (queue_empty(qu)) {
    return -1;
  }
  memset((char *)qu->data + qu->front, 0, qu->size);
  qu->front = (qu->front + 1) % qu->capacity;
  return 1;
}

void queue_destroy(Queue **qu) {
  if (*qu == NULL) {
    return;
  }
  if ((*qu)->data != NULL) {
    free((*qu)->data);
    (*qu)->data = NULL;
  }

  free(*qu);
  (*qu) = NULL;
}
